--[[

Node templating functions for portals 

Copyright 2014 Tiberiu CORBU
Authors: Tiberiu CORBU

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
--]]

if not element_portals then
	element_portals = {}
end

local log_inventory_infraction = function(pos, player)
  local meta = minetest.get_meta(pos)
  if not element_portals:has_private_portal_privilege(meta, player) then
    minetest.log("action",
      string.format("%s tried to access a private portal belonging to %s at %s",
        player:get_player_name() or '',
        meta:get_string("owner"),
        minetest.pos_to_string(pos) or ''))
    return true
  end
  return false
end

local log_inventory_action = function(action, pos, player)
  local player_name = player:get_player_name() or ''
  local pos_str = minetest.pos_to_string(pos) or ''
  if action == 'take' then
    return minetest.log("action", string.format("%s takes stuff to portal at %s", player_name, pos))
  end
  if action == 'move' then
    return minetest.log("action", string.format("%s moves stuff to portal at %s", player_name, pos))
  end
  if action == 'put' then
    return minetest.log("action", string.format("%s puts stuff to portal at %s", player_name, pos))
  end
end

local build_definition = function(params, portal_node_name, private, has_fuel)

  local def = {}
  def.after_place_node = function (pos, placer)
    local meta = minetest.get_meta(pos)
    local portal_node_name = minetest.get_node(pos)
    local portal_name = element_portals:create_portal(pos, placer, portal_node_name)
    local placer_name = element_portals:set_owner(meta, placer, portal_name, private)
  end
	def.on_construct = function(pos)
		local meta = minetest.get_meta(pos)
		element_portals:construct(meta, has_fuel)
		element_portals:set_portal_node_meta(meta, params)
	end
  def.on_destruct = function(pos)
		local meta = minetest.get_meta(pos)
		local player = minetest.get_player_by_name(meta:get_string("owner"))
		if meta and player then 
      element_portals:remove_portal_data(pos, player)
		end 
	end
	if has_fuel then
    def.can_dig = function(pos,player)
      local meta = minetest.get_meta(pos);
      local inv = meta:get_inventory()
      return inv:is_empty("fuel") and element_portals:has_private_portal_privilege(meta, player)
              and not minetest.is_protected(pos, player:get_player_name())
    end
    
    if private then
        def.allow_metadata_inventory_move = function(pos, from_list, from_index, to_list, to_index, count, player)
          if log_inventory_infraction(pos, player) then return 0 end
          return count
        end
        def.allow_metadata_inventory_put = function(pos, listname, index, stack, player)
          if log_inventory_infraction(pos, player) then return 0 end
          return stack:get_count()
        end
        def.allow_metadata_inventory_take = function(pos, listname, index, stack, player)
          if log_inventory_infraction(pos, player) then return 0 end
          return stack:get_count()
        end  
    end
    
    def.on_metadata_inventory_move = function(pos, from_list, from_index, to_list, to_index, count, player)
		element_portals:show_portal_form(pos, player)
        element_portals:show_portal_form(pos, player)	
        log_inventory_action('move', pos, player)
    end
    def.on_metadata_inventory_put = function(pos, listname, index, stack, player)
    	element_portals:show_portal_form(pos, player)	
      log_inventory_action('put', pos, player)
    end
    def.on_metadata_inventory_take = function(pos, listname, index, stack, player)
        element_portals:show_portal_form(pos, player)
        log_inventory_action('take', pos, player)
    end
    
    def.on_rightclick = function(pos, node, clicker)
      element_portals:show_portal_form(pos, clicker)
    end
  else
    def.can_dig = function(pos, player)
      local meta = minetest.get_meta(pos)
      return element_portals:has_private_portal_privilege(meta, player) and not minetest.is_protected(pos, player:get_player_name())
    end
    def.on_rightclick = function(pos, node, clicker)
      element_portals:show_out_portal_form(pos,  clicker)
    end
  end
  return def

end

------------------------------------------------------------------------
------------------------ PUBLIC PORTAL NODE ---------------------------
------------------------------------------------------------------------

-- creates a boilerplate for public portals - adds placer in meta
function element_portals:build_public_node_o_template (params, portal_node_name)
	return build_definition(params, portal_node_name, false, false)
end

-- creates a boilerplate for public portals - adds placer in meta
function element_portals:build_public_node_io_template (params, portal_node_name)
	return build_definition(params, portal_node_name, false, true)
end

local build_public_node_template = function(params, name)
	local node_template
	if params.portal_type == element_portals.IN_OUT_PORTAL 
		or params.portal_type == element_portals.IN_PORTAL
		or params.portal_type == element_portals.IN_RANDOM_PORTAL
		then 
		 node_template = element_portals:build_public_node_io_template(params, name)
	else	
		 node_template = element_portals:build_public_node_o_template(params, name)
	end
	return node_template
end


function element_portals:register_public_portal_node(name, overwrites, params)
	local node_template = build_public_node_template(params, name)
	extent_and_register_node(node_template, name, overwrites, params)
end

------------------------------------------------------------------------
------------------------ PRIVATE PORTAL NODE ---------------------------
------------------------------------------------------------------------


-- creates a boilerplate for private portals - adds owner in meta and allows only private use   
function element_portals:build_private_node_o_template (params, portal_node_name)
	return build_definition(params, portal_node_name, true, false)
end

-- creates a boilerplate for private portals - adds owner in meta and allows only private use   
function element_portals:build_private_node_io_template (params, portal_node_name)
	return build_definition(params, portal_node_name, true, true)
end

local build_private_node_template = function(params, name)
	local node_template
	if params.portal_type == element_portals.IN_OUT_PORTAL 
		or params.portal_type == element_portals.IN_PORTAL
		or params.portal_type == element_portals.IN_RANDOM_PORTAL
		then 
		 node_template = element_portals:build_private_node_io_template(params, name)
	else	
		 node_template = element_portals:build_private_node_o_template(params, name)
	end
	return node_template
end
 
function element_portals:register_private_portal_node(name, overwrites, params)
	local node_template = build_private_node_template(params, name)
	extent_and_register_node(node_template ,name, overwrites, params )
end

------------------------------------------------------------------------
------------------------ NODE COMMON LOGIC -----------------------------
------------------------------------------------------------------------

function extent_and_register_node(node_template, name, overwrites, params)
	local node = {}
	for k,v in pairs(node_template) do
		node[k]=v
	end
	for k,v in pairs(overwrites) do
		node[k]=v
	end
	
	element_portals:register_portal(name, params)
	
	-- register node here
	minetest.register_node(name, node)
end
